package com.doge.walknovel.widgets.imagecropper

import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import androidx.core.content.FileProvider
import androidx.core.net.toFile
import com.doge.wnpro.R
import com.doge.walknovel.core.BaseFragment
import com.doge.walknovel.utils.*
import okio.*
import java.io.File
import java.io.FileInputStream
import java.io.FileNotFoundException

class PickImageFragment : BaseFragment() {
    companion object {
        private const val REQUEST_CODE_ALBUM = 100 // 选择文件
        private const val REQUEST_CODE_CAMERA = 102 // 拍照
        private const val EXTRA_CROP_PREVIEW_CIRCLE = "EXTRA_PREVIEW_CIRCLE"
        private const val EXTRA_TYPE = "EXTRA_TYPE"
        private const val EXTRA_CROP_WIDTH = "EXTRA_CROP_WIDTH"
        private const val EXTRA_CROP_HEIGHT = "EXTRA_CROP_HEIGHT"
        const val TYPE_ALBUM = 1
        const val TYPE_CAMERA = 2

        fun newInstance(
            type: Int,
            cropWidth: Int,
            cropHeight: Int,
            cropPreviewCircle: Boolean = true
        ): PickImageFragment {
            return PickImageFragment().apply {
                arguments = Bundle().apply {
                    putInt(EXTRA_TYPE, type)
                    putInt(EXTRA_CROP_WIDTH, cropWidth)
                    putInt(EXTRA_CROP_HEIGHT, cropHeight)
                    putBoolean(EXTRA_CROP_PREVIEW_CIRCLE, cropPreviewCircle)
                }
            }
        }
    }

    private val type by lazy { arguments?.getInt(EXTRA_TYPE)!! }
    private val previewCircle by lazy { arguments?.getBoolean(EXTRA_CROP_PREVIEW_CIRCLE)!! }
    private val cropWidth by lazy { arguments?.getInt(EXTRA_CROP_WIDTH)!! }
    private val cropHeight by lazy { arguments?.getInt(EXTRA_CROP_HEIGHT)!! }
    private var mCameraResult: File? = null // 拍照后得到的图片


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        when (type) {
            TYPE_ALBUM -> {
                requirePermission(
                    listOf(
                        android.Manifest.permission.READ_EXTERNAL_STORAGE,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE
                    )
                ) {
                    album()
                }
            }
            TYPE_CAMERA -> {
                requirePermission(
                    listOf(
                        android.Manifest.permission.READ_EXTERNAL_STORAGE,
                        android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        android.Manifest.permission.CAMERA
                    )
                ) {
                    camera()
                }
            }
            else -> throw IllegalArgumentException("not support pick image type $type")
        }
    }

    private fun album() {
        val intent = Intent()
        intent.action = Intent.ACTION_PICK
        intent.data = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        intent.type = "image/*"
        startActivityForResult(
            Intent.createChooser(intent, getString(R.string.pick_image)),
            REQUEST_CODE_ALBUM
        )
    }

    private fun camera() {
        try {
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            val fileName = "${System.currentTimeMillis()}.png"
            val file = File(FileUtils.cacheDir("images"), fileName)
            if (!file.exists()) file.createNewFile()
            mCameraResult = file
            val uri: Uri = if (Build.VERSION.SDK_INT >= 24) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                FileProvider.getUriForFile(requireContext(), ApiCompat.fileProvider, file)
            } else {
                Uri.fromFile(file)
            }
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
            startActivityForResult(intent, REQUEST_CODE_CAMERA)
        } catch (e: Throwable) {
            e.printStackTrace()
            toast(R.string.camera_permissions_are_disabled)
        }
    }

    private fun crop(uri: Uri?) {
        if (uri == null) return
        val activity = activity ?: return
        val cropper = ImageCropper.Helper.with(activity)
            .setTitle(getString(R.string.crop_image))
            .setTranslucentStatusHeight(statusBarHeight)
            .setCallback(object : ImageCropper.Callback {
                override fun onPictureCropOut(bitmap: Bitmap, tag: String?) {
                    val cropFileName = "${System.currentTimeMillis()}.png"
                    val file = File(FileUtils.cacheDir("images"), cropFileName)
                    if (!file.exists()) file.createNewFile()
                    BitmapUtils.saveBitmap(bitmap, file)
                    callback(file)
                }
            }).create()

        cropper.crop(uri, cropWidth, cropHeight, previewCircle, "")
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode == Activity.RESULT_OK) {
            when (requestCode) {
                REQUEST_CODE_CAMERA -> {
                    val cameraResult = mCameraResult ?: return
                    val degree = BitmapUtils.readPictureDegree(cameraResult.absolutePath)
                    if (degree != 0) {
                        var bitmap = BitmapUtils.getBitmapFromFile(
                            cameraResult.absolutePath,
                            screenHeight,
                            screenWidth
                        )
                        bitmap = BitmapUtils.rotateBitmap(degree, bitmap)
                        BitmapUtils.saveBitmap(bitmap, cameraResult)
                    }
                    crop(cameraResult.uri)
                }
                REQUEST_CODE_ALBUM -> {
                    val copied: File = if (Build.VERSION.SDK_INT >= 29) {
                        val resultUri = data?.data ?: return
                        val copiedFileName = "${System.currentTimeMillis()}.png"
                        val file = File(FileUtils.cacheDir("images"), copiedFileName)
                        if (!file.exists()) file.createNewFile()
                        val copiedPath = file.absolutePath
                        copyFileAndroid10(resultUri, copiedPath) ?: return
                    } else {
                        val resultPath = data?.data?.let { getPath(it) } ?: return
                        val copiedFileName = "${System.currentTimeMillis()}.png"
                        val file = File(FileUtils.cacheDir("images"), copiedFileName)
                        if (!file.exists()) file.createNewFile()
                        val copiedPath = file.absolutePath
                        copyFile(File(resultPath), copiedPath) ?: return
                    }
                    crop(copied.uri)
                }
            }
        }
    }

    private fun callback(file: File) {
        log("callback crop over  ${file.absolutePath} ")
        PickImageHelper.dispatchResult(file)
    }
}

private fun getPath(uri: Uri?): String? {
    if (uri == null) return null
    return UriUtils.getRealPathFromUri(appContext, uri)
}

private fun copyFile(
    sourceFile: File,
    targetFilePath: String
): File? {
    val source = sourceFile.source()
    return writeToFile(source, targetFilePath)
}

private fun copyFileAndroid10(
    sourceUri: Uri,
    targetFilePath: String
): File? {
    log("copyFileAndroid10【${Build.VERSION.SDK_INT >= 29}】 ${sourceUri.path} to $targetFilePath")
    if (Build.VERSION.SDK_INT >= 29) {
        // android 10
        try {
            val fileDescriptor = appContext.contentResolver.openFile(
                sourceUri, "r", null
            ) ?: return null
            val input = FileInputStream(fileDescriptor.fileDescriptor)
            val source = input.source()
            return writeToFile(source, targetFilePath)
        } catch (e: Throwable) {
            // handle error
            e.printStackTrace()
            return null
        }
    } else {
        return copyFile(sourceUri.toFile(), targetFilePath)
    }
}

private fun writeToFile(source: Source, filePath: String): File? {
    var bufferedSink: BufferedSink? = null
    var file: File? = null
    try {
        file = File(filePath)
        if (file.parentFile?.exists() != true) {
            file.parentFile?.mkdirs()
        }
        bufferedSink = file.sink().buffer()
        bufferedSink.writeAll(source)
        source.close()
    } catch (e: Throwable) {
    } finally {
        closeQuietly(bufferedSink)
    }
    log("writeToFile over $file")
    return file
}


